package com.newsee.remote.common.utils.http;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Http客户端执行器
 *
 * @author HP
 */
@Component
@Slf4j
public class HttpClientExecutor {
    private static HttpClientExecutor sThis;

    private final HttpClientTemplate httpClientTemplate;

    public HttpClientExecutor(HttpClientTemplate httpClientTemplate) {
        this.httpClientTemplate = httpClientTemplate;
    }

    /**
     * 发送POST请求
     *
     * @param url    请求地址
     * @param params 参数
     * @return 响应数据
     */
    public static String doPost(String url, Map<String, String> params) {
        String response = StringUtils.EMPTY;
        try {
            String jsonParam = JSON.toJSONString(params);
            log.info("url={}, params(toJson)={}", url, jsonParam);
            response = sThis.httpClientTemplate.doPost(url, params);
            log.error("url={}, response={}", url, response);
        } catch (IOException e) {
            log.warn(e.getMessage());
        }
        return response;
    }

    /**
     * 发送POST请求
     *
     * @param url     请求地址
     * @param params  参数
     * @param timeout 超时
     * @return 响应数据
     * @throws IOException
     */
    public static String doPost(String url, Map<String, String> params,
                                int timeout) throws IOException {
        String response;
        try {
            String jsonParam = JSON.toJSONString(params);
            log.info(
                    "url={}, params(toJson)={} timeout={}", url, jsonParam,
                    timeout);
            long time = System.currentTimeMillis();
            response = sThis.httpClientTemplate.doPost(url, params, null,
                    timeout);
            time = System.currentTimeMillis() - time;
            log.info(
                    "url={}, response={} timeout={} time={}", url, response,
                    timeout, time);
        } catch (IOException e) {
            log.error("doPost url={}", url);
            throw e;
        }
        return response;
    }

    /**
     * 发送POST请求
     *
     * @param url     请求地址
     * @param params  参数
     * @param timeout 超时
     * @return 响应数据
     * @throws IOException
     */
    public static String doPost(String url, Map<String, String> headers,
                                Map<String, String> params, int timeout) throws IOException {
        String response;
        try {
            String jsonParam = JSON.toJSONString(params);
            log.info(
                    "url={}, headers={} params(toJson)={} timeout={}", url,
                    JSON.toJSONString(headers), jsonParam, timeout);
            long time = System.currentTimeMillis();
            response = sThis.httpClientTemplate.doPost(url, headers, params,
                    "utf-8", timeout);
            time = System.currentTimeMillis() - time;
            log.info(
                    "url={}, response={} timeout={} time={}", url, response,
                    timeout, time);
        } catch (IOException e) {
            log.error("doPost url={}", url);
            throw e;
        }
        return response;
    }

    /**
     * 发送POST请求
     *
     * @param url  请求地址
     * @param data json数据
     * @return 响应数据
     */
    public static String doPostJson(String url, Object data) {
        String response = StringUtils.EMPTY;
        try {
            String jsonParam = JSON.toJSONString(data);
            log.info("url={}, params(toJson)={}", url, jsonParam);
            response = sThis.httpClientTemplate.doPostJson(url, data);
            log.info("url={}, response={}", url, response);
        } catch (IOException e) {
            log.warn(e.getMessage());
        }
        return response;
    }

    /**
     * 发送POST请求
     *
     * @param url     请求地址
     * @param data    json数据
     * @param timeout 超时
     * @return 响应数据
     * @throws IOException
     */
    public static String doPostJson(String url, Object data, int timeout)
            throws IOException {
        String response;
        try {
            String jsonParam = JSON.toJSONString(data);
            log.info(
                    "url={}, params(toJson)={} timeout={}", url, jsonParam,
                    timeout);
            long time = System.currentTimeMillis();
            response = sThis.httpClientTemplate.doPostJson(url, data, null,
                    timeout);
            time = System.currentTimeMillis() - time;
            log.info(
                    "url={}, response={} timeout={} time={}", url, response,
                    timeout, time);
        } catch (IOException e) {
            log.error("doPostJson url={}", url);
            throw e;
        }
        return response;
    }

    /**
     * 发送GET请求
     *
     * @param url 请求地址
     * @return 响应数据
     */
    public static String doGet(String url) {
        String response = StringUtils.EMPTY;
        try {
            log.info("url={}", url);
            response = sThis.httpClientTemplate.doGet(url);
            log.info("url={}, response={}", url, response);
        } catch (IOException e) {
            log.warn(e.getMessage());
        }
        return response;
    }

    /**
     * 发送GET请求
     *
     * @param url    请求地址
     * @param params 参数
     * @return 响应数据
     */
    public static String doGet(String url, Map<String, String> params) {
        String response = StringUtils.EMPTY;
        try {
            String jsonParam = JSON.toJSONString(params);
            log.info("url={}, params(toJson)={}", url, jsonParam);
            response = sThis.httpClientTemplate.doGet(url, params);
            log.info("url={}, response={}", url, response);
        } catch (IOException e) {
            log.warn(e.getMessage());
        }
        return response;
    }

    /**
     * 发送GET请求
     *
     * @param url    请求地址
     * @param params 参数
     * @return 响应数据
     */
    public static String doGet(String url, Map<String, String> params, Map<String, String> headers) {
        String response = StringUtils.EMPTY;
        try {
            String jsonParam = JSON.toJSONString(params);
            log.info("url={}, params(toJson)={}", url, jsonParam);
            response = sThis.httpClientTemplate.doGet(url, params, headers);
            log.info("url={}, response={}", url, response);
        } catch (IOException e) {
            log.warn(e.getMessage());
        }
        return response;
    }

    /**
     * 发送GET请求
     *
     * @param url     请求地址
     * @param params  参数
     * @param timeout 超时
     * @return 响应数据
     * @throws IOException
     */
    public static String doGet(String url, Map<String, String> params,
                               int timeout) throws IOException {
        String response;
        try {
            String jsonParam = JSON.toJSONString(params);
            log.info(
                    "url={}, params(toJson)={} timeout={}", url, jsonParam,
                    timeout);
            long time = System.currentTimeMillis();
            response = sThis.httpClientTemplate.doGet(url, params, null,
                    timeout);
            time = System.currentTimeMillis() - time;
            log.info(
                    "url={}, response={} timeout={} time={}", url, response,
                    timeout, time);
        } catch (IOException e) {
            log.error("doGet url={}", url);
            throw e;
        }
        return response;
    }


    /**
     * 下载请求
     *
     * @param url 请求地址
     * @param key 下载资源标识
     * @return 二进制数据
     */
    public static byte[] download(String url, String key) {
        byte[] response = null;
        try {
            log.info("url={}, key={}", url, key);
            response = sThis.httpClientTemplate.doGetDownload(url, key);
            log.info("url={}, key={}", url, key);
        } catch (IOException e) {
            log.warn(e.getMessage());
        }
        return response;
    }

    @PostConstruct
    public void init() {
        sThis = this;
    }


    /**
     * 执行HttpPost请求
     *
     * @param url    请求路径
     * @param params 参数
     * @return 结果
     */
    public static String httpPost(String url, Map<String, String> params) {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        String result = null;
        try {
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
            if (null != params && params.size() > 0) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    if (key == null || value == null) {
                        continue;
                    }
                    NameValuePair pair = new BasicNameValuePair(key, value);
                    nameValuePairs.add(pair);
                }
            }
            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
            httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
            // 执行请求
            response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if (null != entity) {
                log.info("url={}, params(toJson)={}", url, params);
                result = EntityUtils.toString(entity, ContentType.getOrDefault(entity).getCharset());
                log.info("执行请求完毕：" + result);
                EntityUtils.consume(entity);
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                log.error("请求通信[\" + reqURL + \"]时网络时，关闭异常,堆栈轨迹如下", e);
            }
            httpPost.releaseConnection();
        }
        return result;
    }
}
